<template>
	<div>
		<canvas ref="canvas" :width="width" :height="height" class="canvas"></canvas>
	</div>
</template>
<script>
  import QR from './qrcode';

  export default {
    name: 'CanvasPoster',
    components: {},
    props: {
      painting: {
        type: Object,
        value: {}
      }
    },
    computed: {},
    watch: {
      painting: {
        handler: 'handlePaint',
        deep: true,
        immediate: true
      },
    },
    data() {
      return {
        showCanvas: false,
        width: 100,
        height: 100,
        imageList: [],
        isPainting: false,
        canvas: null,
        ctx: null
      }
    },

    mounted() {
      this.$nextTick(() => {
        this.canvas = this.$refs.canvas // 指定canvas
        this.ctx = this.canvas.getContext("2d")//设置2D渲染区域
      })
    },
    methods: {
      // 开始绘图
      handlePaint(newVal, oldVal) {
        if (newVal.views && newVal !== oldVal) {
          const {width, height, views} = this.painting
          this.width = width
          this.height = height
          const inter = setInterval(() => {
            if (this.ctx) {
              clearInterval(inter)
              // 重新绘图
              this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
              this.ctx.save()
              this.getImages(views)
            }
          }, 100)
        }
      },
      //加载图片
      loadImage(url) {
        return new Promise((resolve, reject) => {
          const img = new Image()
          img.setAttribute('crossorigin', 'anonymous');
          img.onload = () => resolve(img)
          img.onerror = () => reject(`下载图片失败 ${url}`)
          img.src = url
        })
      },
      // 加载图片
      getImages(views) {
        const imageList = []
        for (let i = 0; i < views.length; i++) {
          if (views[i].type === 'image') {
            imageList.push(this.loadImage(views[i].url))
          }
        }
        Promise.all(imageList).then(res => {
          this.imageList = res
          this.startPainting()
        }).catch((err) => {
          this.$emit('fail', err)
        })
      },
      startPainting() {
        const {views} = this.painting
        for (let i = 0, imageIndex = 0; i < views.length; i++) {
          if (views[i].type === 'image') {
            this.drawImage({
              ...views[i],
              img: this.imageList[imageIndex]
            })
            imageIndex++
          } else if (views[i].type === 'text') {
            this.drawText(views[i])
          } else if (views[i].type === 'rect') {
            this.drawRect(views[i])
          } else if (views[i].type === 'qrcode') {
            this.drawQRCode(views[i])
          }
        }
        var imageBase64 = this.canvas.toDataURL("image/png")
        this.$emit('success', (this.painting.flag !== undefined && this.painting.flag !== null) ? {flag:this.painting.flag,img:imageBase64}:imageBase64)

      },
      /**
       * 根据 radius 进行裁减
       */
      _doClip(left, top, width, height, radius) {
        this.ctx.beginPath()
        // 左上角
        this.ctx.arc(left + radius, top + radius, radius, Math.PI, Math.PI * 1.5)
        // border-top
        this.ctx.moveTo(left + radius, top)
        this.ctx.lineTo(left + width - radius, top)
        this.ctx.lineTo(left + width, top + radius)
        // 右上角
        this.ctx.arc(left + width - radius, top + radius, radius, Math.PI * 1.5, Math.PI * 2)
        // border-right
        this.ctx.lineTo(left + width, top + height - radius)
        this.ctx.lineTo(left + width - radius, top + height)
        // 右下角
        this.ctx.arc(left + width - radius, top + height - radius, radius, 0, Math.PI * 0.5)
        // border-bottom
        this.ctx.lineTo(left + radius, top + height);
        this.ctx.lineTo(left, top + height - radius)
        // 左下角
        this.ctx.arc(left + radius, top + height - radius, radius, Math.PI * 0.5, Math.PI)
        // border-left
        this.ctx.lineTo(left, top + radius);
        this.ctx.lineTo(left + radius, top)
        // 这里是使用 fill 还是 stroke都可以，二选一即可，但是需要与上面对应
        this.ctx.fill()
        this.ctx.closePath()

      },
      _doRoate(left, top, height, width, deg) {
        this.ctx.translate(left + width / 2, top + height / 2)
        this.ctx.rotate(deg * Math.PI / 180)
      },
      drawImage(params) {
        this.ctx.save()
        const {img, top = 0, left = 0, width = 0, height = 0, radius = 0, deg = 0} = params
        if (radius) {
          this._doClip(left, top, width, height, radius)
          this.ctx.clip()
          this.ctx.drawImage(img, left, top, width, height)
        } else {
          if (deg !== 0) {
            this._doRoate(left, top, height, width, deg)
            this.ctx.drawImage(img, -width / 2, -height / 2, width, height)
          } else {
            this.ctx.drawImage(img, left, top, width, height)
          }
        }
        this.ctx.restore()
      },
      drawQRCode(params) {
        this.ctx.save()
        const {width = 0, height = 0, left = 0, top = 0, content, background, color} = params
        QR.draw(content, this.ctx, left, top, width, height, background, color)
        this.ctx.restore()
      },

      // 写字
      drawText(params) {
        this.ctx.save()
        const {
          MaxLineNumber = 2,
          breakWord = false,
          color = 'black',
          content = '',
          fontSize = 16,
          top = 0,
          left = 0,
          lineHeight = 20,
          textAlign = 'left',
          width,
          bolder = false,
          textDecoration = 'none'
        } = params

        this.ctx.beginPath()
        // this.ctx.textBaseline = 'top'
        this.ctx.textBaseline = "Bottom"
        this.ctx.textAlign = textAlign
        this.ctx.fillStyle = color
        //  this.ctx.font = "normal 36px Arial";
        this.ctx.font = `normal ${fontSize}px Arial`;
        //  top + fontSize  解决 this.ctx.textBaseline = 'top'问题
        const textTop = top + fontSize
        if (!breakWord) {
          this.ctx.fillText(content, left, textTop)
          this.drawTextLine(left, textTop, textDecoration, color, fontSize, content)
        } else {
          let fillText = ''
          let fillTop = textTop
          let lineNum = 1
          for (let i = 0; i < content.length; i++) {
            fillText += [content[i]]
            if (this.ctx.measureText(fillText).width > width) {
              if (lineNum === MaxLineNumber) {
                if (i !== content.length) {
                  fillText = fillText.substring(0, fillText.length - 1) + '...'
                  this.ctx.fillText(fillText, left, fillTop)
                  this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText)
                  fillText = ''
                  break
                }
              }
              this.ctx.fillText(fillText, left, fillTop)
              this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText)
              fillText = ''
              fillTop += lineHeight
              lineNum++
            }
          }
          this.ctx.fillText(fillText, left, fillTop)
          this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText)
        }
        this.ctx.restore()
        if (bolder) {
          this.drawText({
            ...params,
            left: left + 0.3,
            top: top + 0.3,
            bolder: false,
            textDecoration: 'none'
          })
        }
      },
      // 画直线
      drawTextLine(left, top, textDecoration, color, fontSize, content) {
        if (textDecoration === 'underline') {
          this.drawRect({
            background: color,
            top: top,
            left: left - 1,
            width: this.ctx.measureText(content).width + 3,
            height: 1
          })
        } else if (textDecoration === 'line-through') {
          this.drawRect({
            background: color,
            top: top - fontSize / 3,
            left: left - 1,
            width: this.ctx.measureText(content).width + 3,
            height: 1
          })

        }
      },
      _getAngle(angle) {
        return Number(angle) * Math.PI / 180;
      },
      // 画矩形
      drawRect(params) {
        this.ctx.save()
        const {background = 'white', top = 0, left = 0, width = 0, height = 0, radius = 0, deg = 0} = params
        this.ctx.fillStyle = background
        if (radius) {
          this._doClip(left, top, width, height, radius)
        } else {
          if (deg !== 0) {
            this._doRoate(left, top, height, width, deg)
            this.ctx.fillRect(-width / 2, -height / 2, width, height)
          } else {
            this.ctx.fillRect(left, top, width, height)
          }
          // this.ctx.fillRect(left, top, width, height)
        }
        this.ctx.restore()
      },

    }
  }

</script>
<style scoped>
	.canvas {
		position: fixed;
		top: 2000px;
	}
</style>